home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / wstr.exe / WSTR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-26  |  21.4 KB  |  1,182 lines

  1. #include <stdlib.h>
  2. #include <math.h>
  3. #include <ctype.h>
  4. #include <WStr.h>
  5. #pragma hdrstop
  6.  
  7. // copyright (c) 1992, 1993 by Paul Wheaton
  8.  
  9. //.parse
  10.  
  11. /////////  BaseString class
  12.  
  13. static char GarbageChar;
  14.  
  15. char& BaseString::operator[](int Index)
  16.   {
  17.     if (Index >= Len)
  18.       {
  19.         GarbageChar=0;
  20.         return GarbageChar;
  21.       }
  22.     return P[Index];
  23.   }
  24.  
  25.   /*
  26.  
  27.   The idea here is that if a programmer were to give an index out of range
  28.   then they won't be messing up something.  If they wrote "S[5]='X'" and S
  29.   was a string of length 2, then GarbageChar would be set to 'X' and S would
  30.   be unaffected.  "MyChar=S[5]" would result in MyChar being assigned 0.
  31.  
  32.   */
  33.  
  34. //.parse
  35.  
  36. Bool BaseString::operator==(const BaseString& S) const
  37.   {
  38.     if (Len != S.Len) return No;
  39.     int I = Len/(sizeof(int));
  40.     const int* P1 = (const int*)P;
  41.     const int* P2 = (const int*)S.P;
  42.     while (I!=0)
  43.       {
  44.         if (*P1 != *P2) return No;
  45.         P1++;
  46.         P2++;
  47.         I--;
  48.       }
  49.     I= Len%(sizeof(int));
  50.     if (I!=0)
  51.       {
  52.         const char* PP1=(const char*)P1;
  53.         const char* PP2=(const char*)P2;
  54.         while (I!=0)
  55.           {
  56.             if (*PP1 != *PP2) return No;
  57.             PP1++;
  58.             PP2++;
  59.             I--;
  60.           }
  61.       }
  62.     return Yes;
  63.   }
  64.  
  65. //.parse
  66.  
  67. void BaseString::ToLower()
  68.   {
  69.     int I = Len;
  70.     char* Q = P;
  71.     while (I--) { *Q = tolower(*Q); Q++; }
  72.   }
  73.  
  74. //.parse
  75.  
  76. void BaseString::ToUpper()
  77.   {
  78.     register int I = Len;
  79.     register char* Q = P;
  80.     while (I--) { *Q = toupper(*Q); Q++; }
  81.   }
  82.  
  83. //.parse
  84.  
  85. int BaseString::Index(char SearchChar, int StartIndex) const
  86.   {
  87.     if (StartIndex>=Len) return(NotFound);
  88.     int I=StartIndex;
  89.     while ((I<Len) && (P[I]!=SearchChar)) I++;
  90.     if (I==Len) return(NotFound);
  91.     else return(I);
  92.   }
  93.  
  94. //.parse
  95.  
  96. int BaseString::Index(const char* SearchStr, int StartIndex) const
  97.   {
  98.     if (StartIndex>=Len) return(NotFound);
  99.     char* Pos=strstr(P+StartIndex,SearchStr);
  100.     if (Pos==NULL) return NotFound;
  101.     else return int(Pos-P);
  102.   }
  103.  
  104. //.parse
  105.  
  106. int BaseString::Count(char C) const
  107.   {
  108.     int Num=0;
  109.     int I;
  110.     For(I,Len) if(P[I]==C) Num++;
  111.     return Num;
  112.   }
  113.  
  114. //.parse
  115.  
  116. void BaseString::Delete(int Index,int Length)
  117.   {
  118.     // *this=BeforeSub(Index)+FromSub(Index+Length);
  119.     int S=Index+Length;
  120.     while (S<Len)
  121.       {
  122.         P[Index]=P[S];
  123.         Index++;
  124.         S++;
  125.       }
  126.     P[Index]='\0';
  127.     Len=Index;
  128.   }
  129.  
  130. //.parse
  131.  
  132. void BaseString::DeleteLast()
  133.   {
  134.     if (Len>0)
  135.       {
  136.         Len--;
  137.         P[Len]='\0';
  138.       }
  139.   }
  140.  
  141. //.parse
  142.  
  143. void BaseString::Trim()
  144.   {
  145.     if (Len==0) return;
  146.     int I=0;
  147.     while ((P[I]==' ')&&(I<Len)) I++;
  148.     if (I>0) Delete(0,I);
  149.     if (Len==0) return;
  150.     TrimTrail();
  151.   }
  152.  
  153. //.parse
  154.  
  155. void BaseString::TrimTrailTo(char C)
  156.   {
  157.     if (Len>0)
  158.       {
  159.         Len--;
  160.         while ((P[Len]!=C)&&(Len>0)) Len--;
  161.         P[Len]='\0';
  162.       }
  163.   }
  164.  
  165. //.parse
  166.  
  167. void BaseString::TrimTrail()
  168.   {
  169.     if (Len>0)
  170.       {
  171.         Len--;
  172.         while ((P[Len]==' ')&&(Len>0)) Len--;
  173.         Len++;
  174.         P[Len]='\0';
  175.       }
  176.   }
  177.  
  178. //.parse
  179.  
  180. char BaseString::At(int Index) const
  181.   {
  182.     if (Index>=Len) return '\0';
  183.     return (P[Index]);
  184.   }
  185.  
  186. //.parse
  187.  
  188. char BaseString::Last() const
  189.   {
  190.     if (Len==0) return '\0';
  191.     else return P[Len-1];
  192.   }
  193.  
  194. ///////////  String class
  195.  
  196. //.parse
  197.  
  198. void String::ReNew(int NewCapacity)  // replaces ANSI-C realloc
  199.   {
  200.     #ifdef MAJORBBS
  201.       char* P2=(char*)malloc(NewCapacity);
  202.     #else
  203.       char* P2=new char[NewCapacity];
  204.     #endif
  205.     if (P2==NULL) FatalError("out of string mem rn");
  206.     strncpy(P2,P,NewCapacity-1);
  207.     #ifdef MAJORBBS
  208.       free(P);
  209.     #else
  210.       delete(P);
  211.     #endif
  212.     P=P2;
  213.     P[NewCapacity-1]=0;
  214.   }
  215.  
  216. void String::New()
  217.   {
  218.     #ifdef MAJORBBS
  219.       P = (char*)malloc(Alloc);
  220.     #else
  221.       P = new char[Alloc];
  222.     #endif
  223.     if (P==NULL) FatalError("out of string mem");
  224.   }
  225.  
  226.  
  227. //.parse
  228.  
  229. String::String(const char& C, int L, int Extra)
  230.   {
  231.     Len = L;
  232.     Alloc = Len + Extra + 1;
  233.     New();
  234.     register int I=Len;
  235.     P[I] = 0;
  236.     while (I) P[--I] = C;
  237.   }
  238.  
  239. //.parse
  240.  
  241. String::String(int Extra)
  242.   {
  243.     Len = 0;
  244.     Alloc = Extra + 1;
  245.     New();
  246.     *P = 0;
  247.   }
  248.  
  249. //.parse
  250.  
  251. String::String(const char* CS, int Extra)
  252.   {
  253.     Len = strlen(CS);
  254.     Alloc = Len + Extra + 1;
  255.     New();
  256.     strcpy(P,CS);
  257.   }
  258.  
  259. //.parse
  260.  
  261. String::String(const BaseString& S, int Extra)
  262.   {
  263.     Len = S.Len;
  264.     Alloc = Len + Extra + 1;
  265.     New();
  266.     strcpy(P,S.P);
  267.   }
  268.  
  269. //.parse
  270.  
  271. void String::operator=(const BaseString& S)
  272.   {
  273.     if (P == S.P) return;
  274.     Len = S.Len;
  275.     if (Len >= Alloc)
  276.       {
  277.         #ifdef MAJORBBS
  278.           free(P);
  279.         #else
  280.           delete(P);
  281.         #endif
  282.         Alloc = S.Alloc;
  283.         New();
  284.       }
  285.     strcpy(P,S.P);
  286.   }
  287.  
  288. //.parse
  289.  
  290. void String::operator=(const char* CS)
  291.   {
  292.     Len = strlen(CS);
  293.     if (Len >= Alloc)
  294.       {
  295.         Alloc = Len + DefaultStringExtra + 1;
  296.         #ifdef MAJORBBS
  297.           free(P);
  298.         #else
  299.           delete(P);
  300.         #endif
  301.         New();
  302.       }
  303.     strcpy(P,CS);
  304.   }
  305.  
  306. //.parse
  307.  
  308. void String::operator=(const char C)
  309.   {
  310.     Len=1;
  311.     P[0]=C;
  312.   }
  313.  
  314. //.parse
  315.  
  316. String String::operator+(const String40& S) const
  317.   {
  318.     String T(Len+S.Len+1);
  319.     strcpy(T.P,P);
  320.     strcpy(&(T.P[Len]), S.P);
  321.     T.Len = Len+S.Len;
  322.     return(T);
  323.   }
  324.  
  325. //.parse
  326.  
  327. String String::operator+(const String120& S) const
  328.   {
  329.     String T(Len+S.Len+1);
  330.     strcpy(T.P,P);
  331.     strcpy(&(T.P[Len]), S.P);
  332.     T.Len = Len+S.Len;
  333.     return(T);
  334.   }
  335.  
  336. //.parse
  337.  
  338. String String::operator+(const String& S) const
  339.   {
  340.     String T(Len+S.Len+1);
  341.     strcpy(T.P,P);
  342.     strcpy(&(T.P[Len]), S.P);
  343.     T.Len = Len+S.Len;
  344.     return(T);
  345.   }
  346.  
  347. //.parse
  348.  
  349. String String::operator+(const char* CS) const
  350.   {
  351.     int CSLen = strlen(CS);
  352.     String T(Len+CSLen+1);
  353.     strcpy (T.P,P);
  354.     strcpy (&(T.P[Len]), CS);
  355.     T.Len = Len+CSLen;
  356.     return T;
  357.   }
  358.  
  359. //.parse
  360.  
  361. String String::operator+(char C) const
  362.   {
  363.     String S(*this,1);
  364.     S.P[Len]=C;
  365.     S.Len++;
  366.     S.P[S.Len]=0;
  367.     return S;
  368.   }
  369.  
  370. //.parse
  371.  
  372. String operator+(const String40& SS, const String& S)
  373.   {
  374.     String T(SS.Length()+S.Len+1);
  375.     strcpy(T.P,(const char*)SS);
  376.     strcpy(&(T.P[SS.Length()]), S.P);
  377.     T.Len = SS.Length()+S.Len;
  378.     return(T);
  379.   }
  380.  
  381. //.parse
  382.  
  383. String operator+(const String120& SS, const String& S)
  384.   {
  385.     String T(SS.Length()+S.Len+1);
  386.     strcpy(T.P,(const char*)SS);
  387.     strcpy(&(T.P[SS.Length()]), S.P);
  388.     T.Len = SS.Length()+S.Len;
  389.     return(T);
  390.   }
  391.  
  392. //.parse
  393.  
  394. String operator+(const char* CS, const String& S)
  395.   {
  396.     int CSLen=strlen(CS);
  397.     String T(int(CSLen+S.Len+1));
  398.     strcpy(T.P,CS);
  399.     strcpy(&(T.P[CSLen]),S.P);
  400.     T.Len = CSLen + S.Len;
  401.     return T;
  402.   }
  403.  
  404. //.parse
  405.  
  406. String operator+(char C, const String& S)
  407.   {
  408.     int NewLen=S.Len+1;
  409.     String T(NewLen);
  410.     T.P[0]=C;
  411.     strcpy(&(T.P[1]),S.P);
  412.     T.Len = NewLen;
  413.     return T;
  414.   }
  415.  
  416. //.parse
  417.  
  418. void String::operator+=(const BaseString& S)
  419.   {
  420.     if (S.Len==0) return;
  421.     int NewLen=Len+S.Len;
  422.     if (Alloc <= NewLen)
  423.       {
  424.         Alloc = NewLen+1;
  425.         ReNew(Alloc);
  426.       }
  427.     strcpy(&P[Len],S.P);
  428.     Len += S.Len;
  429.   }
  430.  
  431. //.parse
  432.  
  433. void String::operator+=(const char* CS)
  434.   {
  435.     int CSLen = strlen(CS);
  436.     if (CSLen==0) return;
  437.     int NewLen=Len+CSLen;
  438.     if (Alloc <= NewLen)
  439.       {
  440.         Alloc = NewLen+1;
  441.         ReNew(Alloc);
  442.       }
  443.     strcpy(&(P[Len]),CS);
  444.     Len += CSLen;
  445.   }
  446.  
  447. void String::operator+=(char C)
  448.   {
  449.     *this=*this+C;
  450.     /*
  451.     if (Alloc < Len+2)
  452.       {
  453.         Alloc += (DefaultStringExtra+1);
  454.         ReNew(Alloc);
  455.       }
  456.     P[Len]=C;
  457.     Len++;
  458.     P[Len]=0;
  459.     */
  460.   }
  461.  
  462. //.parse
  463.  
  464. void String::Left(int NewSize)
  465.   {
  466.     if (Len>NewSize)
  467.       {
  468.         Len=NewSize;
  469.         P[Len]=0;
  470.       }
  471.     else *this+=Spaces(NewSize-Len);
  472.   }
  473.  
  474. //.parse
  475.  
  476. void String::Right(int NewSize)
  477.   {
  478.     if (Len>NewSize)
  479.       {
  480.         Len=NewSize;
  481.         P[Len]=0;
  482.       }
  483.     else
  484.       {
  485.         String T=Spaces(NewSize-Len)+(*this);
  486.         *this=T;
  487.       }
  488.   }
  489.  
  490. //.parse
  491.  
  492. void String::Center(int NewSize)
  493.   {
  494.     if (Len>NewSize)
  495.       {
  496.         Len=NewSize;
  497.         P[Len]=0;
  498.       }
  499.     else
  500.       {
  501.         int TotSpaces=NewSize-Len;
  502.         int LeftSpaces=TotSpaces/2;
  503.         *this=Spaces(LeftSpaces)+(*this)+Spaces(TotSpaces-LeftSpaces);
  504.       }
  505.   }
  506.  
  507. //.parse
  508.  
  509. void String::Tail(int NewSize)
  510.   {
  511.     if (Len>NewSize) *this=From(Len-NewSize);
  512.     else *this=Spaces(NewSize-Len)+*this;
  513.   }
  514.  
  515. //.parse
  516.  
  517. int String::ReAlloc(int NewCapacity)
  518.   {
  519.     if (NewCapacity < Len) NewCapacity = Len;
  520.     if (Alloc != NewCapacity+1)
  521.       {
  522.         Alloc = NewCapacity+1;
  523.         ReNew(Alloc);
  524.       }
  525.     return Alloc - 1;
  526.   }
  527.  
  528. //.parse
  529.  
  530. String String::At(int Index, int Length) const
  531.   {
  532.     if (Index>=Len)
  533.       {
  534.         String S="";
  535.         return S;
  536.       }
  537.     if (Index+Length>Len) Length=Len-Index;
  538.     String S(int(Length+1));
  539.     memcpy(S.P,&P[Index],Length);
  540.     S.P[Length]='\0';
  541.     S.Len=Length;
  542.     return S;
  543.   }
  544.  
  545. //.parse
  546.  
  547. void String::Insert(char C,int Index)
  548.   {
  549.     if (Len==0) *this=String(C);
  550.     else if (Index==0) *this=String(C)+(*this);
  551.     else if (Index>=Len) *this+=C;
  552.     else *this=Before(Index)+C+From(Index);
  553.   }
  554.  
  555. void String::Insert(const char* St,int Index)
  556.   {
  557.     *this=Before(Index)+St+From(Index);
  558.   }
  559.  
  560. ////////  StackString class
  561.  
  562. //.parse
  563.  
  564. void StackString::operator=(const BaseString& S)
  565.   {
  566.     if (P == S.P) return;
  567.     Len = Min(S.Len,Alloc-1);
  568.     memcpy(P,S.P,Len);
  569.     P[Len]='\0';
  570.   }
  571.  
  572. void StackString::operator=(const char* CS)
  573.   {
  574.     Len = Min(int(strlen(CS)),Alloc-1);
  575.     memcpy(P,CS,Len);
  576.     P[Len]='\0';
  577.   }
  578.  
  579. void StackString::operator=(const char C)
  580.   {
  581.     Len=1;
  582.     P[0]=C;
  583.   }
  584.  
  585. //.parse
  586.  
  587. void StackString::operator+=(const BaseString& S)
  588.   {
  589.     if (S.Len==0) return;
  590.     int MaxCopy=Alloc-Len-1;
  591.     int CopyLen=Min(MaxCopy,S.Len);
  592.     memcpy(&P[Len],S.P,CopyLen);
  593.     Len+=CopyLen;
  594.     P[Len]='\0';
  595.   }
  596.  
  597. //.parse
  598.  
  599. void StackString::operator+=(const char* CS)
  600.   {
  601.     int CSLen = strlen(CS);
  602.     if (CSLen==0) return;
  603.     int MaxCopy=Alloc-Len-1;
  604.     int CopyLen=Min(MaxCopy,CSLen);
  605.     memcpy(&P[Len],CS,CopyLen);
  606.     Len+=CopyLen;
  607.     P[Len]='\0';
  608.   }
  609.  
  610. //.parse
  611.  
  612. void StackString::operator+=(char C)
  613.   {
  614.     if (Len<(Alloc-1))
  615.       {
  616.         P[Len]=C;
  617.         Len++;
  618.       }
  619.   }
  620.  
  621. //.parse
  622.  
  623. void StackString::Left(int NewSize)
  624.   {
  625.     if (Len>NewSize)
  626.       {
  627.         Len=NewSize;
  628.         P[Len]=0;
  629.       }
  630.     else if (NewSize>Len)
  631.       {
  632.         int End=Min(NewSize,Alloc-1);
  633.         int Dif=End-Len;
  634.         memset(P+Len,' ',Dif);
  635.         Len+=Dif;
  636.         P[Len]='\0';
  637.       }
  638.   }
  639.  
  640. //.parse
  641.  
  642. void StackString::Right(int NewSize)
  643.   {
  644.     if (Len>NewSize)
  645.       {
  646.         Len=NewSize;
  647.         P[Len]=0;
  648.       }
  649.     else if (NewSize>Len)
  650.       {
  651.         int End=Min(NewSize,Alloc-1);
  652.         int Dif=End-Len;
  653.         memmove(P+Dif,P,Len);
  654.         memset(P,' ',Dif);
  655.         Len+=Dif;
  656.         P[Len]='\0';
  657.       }
  658.   }
  659.  
  660. //.parse
  661.  
  662. void StackString::Center(int NewSize)
  663.   {
  664.     if (Len>NewSize)
  665.       {
  666.         Len=NewSize;
  667.         P[Len]=0;
  668.       }
  669.     else
  670.       {
  671.         NewSize=Min(NewSize,Alloc-1);
  672.         Right(((NewSize-Len)/2)+Len);
  673.         Left(NewSize);
  674.       }
  675.   }
  676.  
  677. //.parse
  678.  
  679. void StackString::Tail(int NewSize)
  680.   {
  681.     if (Len>NewSize)
  682.       {
  683.         memmove(P,P+(Len-NewSize),NewSize);
  684.         Len=NewSize;
  685.         P[Len]='\0';
  686.       }
  687.     else Right(NewSize);
  688.   }
  689.  
  690. //.parse
  691.  
  692. void StackString::Sub(StackString& D, int I, int L)
  693.   {
  694.     if ((I+L)>Len) L=Len-I;
  695.     D.Len=L;
  696.     memcpy(D.P,P+I,L);
  697.     D.P[L]='\0';
  698.   }
  699.  
  700. //.parse
  701.  
  702. void StackString::Insert(char C,int Index)
  703.   {
  704.     if ((Len==Alloc-1)&&(Index<Len)) Len--;
  705.     if (Index>=Len)
  706.       {
  707.         P[Len]=C;
  708.         Len++;
  709.       }
  710.     else
  711.       {
  712.         memmove(P+Index+1,P+Index,Len-Index+1);
  713.         P[Index]=C;
  714.         Len++;
  715.       }
  716.     P[Len]='\0';
  717.   }
  718.  
  719. //.parse
  720.  
  721. void StackString::Insert(const char* St,int Index)
  722.   {
  723.     int StLen=strlen(St);
  724.     if (Index>Len) Index=Len;
  725.     int MoveNum=Len-Index;
  726.     int TotLen=StLen+Len;
  727.     int Excess=TotLen-(Alloc-1);
  728.     if (Excess>0)
  729.       {
  730.         MoveNum-=Excess;
  731.         if (MoveNum<0) StLen+=MoveNum;
  732.       }
  733.     if (MoveNum>0)
  734.       {
  735.         memmove(P+Index+StLen,P+Index,MoveNum);
  736.         Len+=MoveNum;
  737.       }
  738.     if (StLen>0)
  739.       {
  740.         memcpy(P+Index,St,StLen);
  741.         Len+=StLen;
  742.       }
  743.     P[Len]='\0';
  744.   }
  745.  
  746. ///////  String40 class
  747.  
  748. //.parse
  749.  
  750. String40::String40()
  751.   {
  752.     P=&Buf[0];
  753.     Buf[0]='\0';
  754.     Len=0;
  755.     Alloc=41;
  756.   }
  757.  
  758. //.parse
  759.  
  760. String40::String40(const char& C, int L)
  761.   {
  762.     P=&Buf[0];
  763.     Alloc=41;
  764.     Len=L;
  765.     if (Len>40) Len=40;
  766.     memset(P,C,Len);
  767.     Buf[Len]='\0';
  768.   }
  769.  
  770. //.parse
  771.  
  772. String40::String40(const char* CS)
  773.   {
  774.     P=&Buf[0];
  775.     Alloc=41;
  776.     Len=strlen(CS);
  777.     if (Len>40) Len=40;
  778.     memcpy(P,CS,Len);
  779.     Buf[Len]='\0';
  780.   }
  781.  
  782. //.parse
  783.  
  784. String40::String40(const BaseString& BS)
  785.   {
  786.     P=&Buf[0];
  787.     Alloc=41;
  788.     Len=BS.Len;
  789.     if (Len>40) Len=40;
  790.     memcpy(P,BS.P,Len);
  791.     Buf[Len]='\0';
  792.   }
  793.  
  794. //.parse
  795.  
  796. String40 String40::operator+(const String40& S) const
  797.   {String40 T(*this); T+=S; return T;}
  798. String40 String40::operator+(const char* S) const
  799.   {String40 T(*this); T+=S; return T;}
  800. String40 String40::operator+(char C) const
  801.   {String40 T(*this); T+=C; return T;}
  802.  
  803. String40 operator+(const char* S1, const String40& S2)
  804.   {String40 T(S1); T+=S2; return T;}
  805. String40 operator+(char C, const String40& S)
  806.   {String40 T(C); T+=S; return T;}
  807.  
  808. String40 String40::At(int Index, int Length) const
  809.   {String40 T; StackString::Sub(T,Index,Length); return T;}
  810.  
  811.  
  812.  
  813. ///////  String120 class
  814.  
  815. //.parse
  816.  
  817. String120::String120()
  818.   {
  819.     P=&Buf[0];
  820.     Buf[0]='\0';
  821.     Len=0;
  822.     Alloc=121;
  823.   }
  824.  
  825. //.parse
  826.  
  827. String120::String120(const char& C, int L)
  828.   {
  829.     P=&Buf[0];
  830.     Alloc=121;
  831.     Len=L;
  832.     if (Len>120) Len=120;
  833.     memset(P,C,Len);
  834.     Buf[Len]='\0';
  835.   }
  836.  
  837. //.parse
  838.  
  839. String120::String120(const char* CS)
  840.   {
  841.     P=&Buf[0];
  842.     Alloc=121;
  843.     Len=strlen(CS);
  844.     if (Len>120) Len=120;
  845.     memcpy(P,CS,Len);
  846.     Buf[Len]='\0';
  847.   }
  848.  
  849. //.parse
  850.  
  851. String120::String120(const BaseString& BS)
  852.   {
  853.     P=&Buf[0];
  854.     Alloc=121;
  855.     Len=BS.Len;
  856.     if (Len>120) Len=120;
  857.     memcpy(P,BS.P,Len);
  858.     Buf[Len]='\0';
  859.   }
  860.  
  861. //.parse
  862.  
  863. String120 String120::operator+(const String40& S) const
  864.   {String120 T(*this); T+=S; return T;}
  865. String120 String120::operator+(const String120& S) const
  866.   {String120 T(*this); T+=S; return T;}
  867. String120 String120::operator+(const char* S) const
  868.   {String120 T(*this); T+=S; return T;}
  869. String120 String120::operator+(char C) const
  870.   {String120 T(*this); T+=C; return T;}
  871.  
  872. String120 operator+(const String40& S1, const String120& S2)
  873.   {String120 T(S1); T+=S2; return T;}
  874. String120 operator+(const char* S1, const String120& S2)
  875.   {String120 T(S1); T+=S2; return T;}
  876. String120 operator+(char C, const String120& S)
  877.   {String120 T(C); T+=S; return T;}
  878.  
  879. String120 String120::At(int Index, int Length) const
  880.   {String120 T; StackString::Sub(T,Index,Length); return T;}
  881.  
  882. String CenterText(const char* CS, int NewSize)
  883.   {
  884.     String S=CS;
  885.     S.Center(NewSize);
  886.     return S;
  887.   }
  888.  
  889. //.parse
  890.  
  891. String Form(int FLen,SLong Val)
  892.   {
  893.     String Mask=TailText("##,###,###,###",FLen);
  894.       //  SLong has 10 significant digits + 1 sign digit
  895.     if (Mask[0]==',') Mask[0]='#';
  896.     String ReturnString=Form(Mask,double(Val));
  897.     return ReturnString;
  898.   }
  899.  
  900. //.parse
  901.  
  902. static Bool DigitToken(char C)
  903.   {
  904.     return ((C=='@') || (C=='#'));
  905.   }
  906.  
  907. static void FindDigitToken(String &S, int &I)
  908.   {
  909.     while (!DigitToken(S[I])) I++;
  910.   }
  911.  
  912. static void DoFillers(String &Mask, int Fillers)
  913.   {
  914.     int I=0;
  915.     while (Fillers)
  916.       {
  917.         FindDigitToken(Mask,I);
  918.         if (Mask[I]=='@') Mask[I]='0';
  919.         else Mask[I]=' ';
  920.         Fillers--;
  921.       }
  922.   }
  923.  
  924. static void DoSpaceFillers(String &Mask, int Fillers)
  925.   {
  926.     int I=0;
  927.     FindDigitToken(Mask,I);
  928.     while (Fillers)
  929.       {
  930.         if (Mask[I]=='#') Fillers--;
  931.         Mask[I]=' ';
  932.         I++;
  933.       }
  934.     if (Mask[I]==',') Mask[I]=' ';
  935.   }
  936.  
  937. static void DoNeg(String &Mask)
  938.   {
  939.     int I=0;
  940.     FindDigitToken(Mask,I);
  941.     if (Mask[I+1]==',')
  942.       {
  943.         Mask[I]=' ';
  944.         I++;
  945.       }
  946.     Mask[I]='-';
  947.   }
  948.  
  949. String Form(const char* M,double Val)
  950.   {
  951.     String Mask=M;
  952.     Bool Negative=(Val<0.0);
  953.     Val=Abs(Val);
  954.     int MaskDecPos=Mask.Index('.'); //  The position of the decimal in Mask
  955.     int MI;  //  Mask Index:  the part of the mask currently being fooled with
  956.     String DecStr="";
  957.     if (MaskDecPos!=NotFound)
  958.       {
  959.         int Digits=0;
  960.         for(MI=MaskDecPos+1;MI<Mask.Length();MI++)
  961.           {
  962.             if (Mask[MI]=='#') Mask[MI]='@';
  963.             if (Mask[MI]=='@') Digits++;
  964.           }
  965.         MI=MaskDecPos+1;
  966.         double D=(Val-floor(Val));
  967.         Val-=D;
  968.         double Mult=pow(10,Digits);
  969.         D*=Mult;
  970.         if (D+0.5>Mult)
  971.           {
  972.             D=0.0;
  973.             Val+=1.0;
  974.           }
  975.         DecStr=Form(Mask.From(MI),D);
  976.           //  recursive call!  This part will be skipped cuz there's no decimal in the mask
  977.         Mask.Left(MI);  //  chop off decimal portion
  978.       }
  979.     int Digits=0;  // the number of digits there are available to fill
  980.     For(MI,Mask.Length())
  981.         if (DigitToken(Mask[MI])) Digits++;
  982.     String IStr=DStr(Val+0.5);  //  convert the integral part to a string
  983.     Bool NegBrackets=(Mask[0]=='<');
  984.     Bool NegCharNeeded=((!NegBrackets)&&(Negative));
  985.     if (NegCharNeeded) Digits--;
  986.     if (IStr.Length()>Digits)  // then fill with *'s
  987.       {
  988.         For(MI,Mask.Length())
  989.             if (DigitToken(Mask[MI])) Mask[MI]='*';
  990.       }
  991.     else
  992.       {
  993.         int Fillers=Digits-IStr.Length();
  994.         MI=0;
  995.         FindDigitToken(Mask,MI);
  996.         if (Mask[MI]=='#')
  997.           {
  998.             DoSpaceFillers(Mask,Fillers);
  999.             if (NegCharNeeded) DoNeg(Mask);
  1000.           }
  1001.         else
  1002.           {
  1003.             if (NegCharNeeded) DoNeg(Mask);
  1004.             DoFillers(Mask,Fillers);
  1005.           }
  1006.         int I;  //  IStr Index
  1007.         For(I,IStr.Length())
  1008.           {
  1009.             FindDigitToken(Mask,MI);
  1010.             Mask[MI]=IStr[I];
  1011.           }
  1012.       }
  1013.     Mask+=DecStr;
  1014.     if (NegBrackets && (!Negative))
  1015.       {
  1016.         Mask[0]=' ';
  1017.         Mask[Mask.Length()-1]=' ';
  1018.       }
  1019.     return (Mask);
  1020.   }
  1021.  
  1022. //.parse
  1023.  
  1024. String Form(int FLen,const double& Val)
  1025.   {
  1026.     String Mask=TailText("#,###,###,###",FLen);
  1027.       //  SLong has 10 significant digits
  1028.     if (Mask[0]==',') Mask[0]='#';
  1029.     String ReturnString=Form(Mask,Val);
  1030.     return ReturnString;
  1031.   }
  1032.  
  1033. //.parse
  1034.  
  1035. String Form(int FLen,const Long& Val)
  1036.   {return Form(FLen,float(Val));}
  1037.  
  1038. String Form(int FLen,const float& Val)
  1039.   {
  1040.     return Form(int(FLen),double(Val));
  1041.   }
  1042.  
  1043. #ifndef MAJORBBS
  1044. String HexStr(Long Num)
  1045.   {
  1046.     char TmpStr[35];
  1047.     ltoa(Num,TmpStr,16);
  1048.     String X=TmpStr;
  1049.     return(X);
  1050.   }
  1051. #endif
  1052.  
  1053. //.parse
  1054.  
  1055. String LeftText(const char* CS, int NewSize)
  1056.   {
  1057.     String S=CS;
  1058.     S.Left(NewSize);
  1059.     return(S);
  1060.   }
  1061.  
  1062. #ifndef MAJORBBS
  1063. String OctalStr(Long Num)
  1064.   {
  1065.     char TmpStr[35];
  1066.     ltoa(Num,TmpStr,8);
  1067.     String X=TmpStr;
  1068.     return(X);
  1069.   }
  1070. #endif
  1071.  
  1072. //.parse
  1073.  
  1074. String StringOf(int HowMany, char What)
  1075.  {
  1076.    String S(What,HowMany,0);
  1077.    return(S);
  1078.  }
  1079.  
  1080. //.parse
  1081.  
  1082. String Str(long Num)
  1083.   {
  1084.     const BuffyLen=11;
  1085.     char Buffy[BuffyLen]="         0";
  1086.     char* BuffyPos=&Buffy[BuffyLen-2];
  1087.     if (Num>0)
  1088.       {
  1089.         while (Num>0)
  1090.           {
  1091.             *BuffyPos=char((Num%10)+48);
  1092.             Num/=10;
  1093.             BuffyPos--;
  1094.           }
  1095.         BuffyPos++;
  1096.       }
  1097.     return String(BuffyPos);
  1098.   }
  1099.  
  1100. //.parse
  1101.  
  1102. String40 CommaStr(long Num)
  1103.   {
  1104.     const BuffyLen=15;
  1105.     char Buffy[BuffyLen]=",,,,,,,,,,,,,0";
  1106.     int I=0;
  1107.     char* BuffyPos=&Buffy[BuffyLen-2];
  1108.     while (Num>0)
  1109.       {
  1110.         *BuffyPos=char((Num%10)+48);
  1111.         Num/=10;
  1112.         BuffyPos--;
  1113.         I++;
  1114.         if (I%3==0) BuffyPos--;
  1115.       }
  1116.     BuffyPos++;
  1117.     if (*BuffyPos==',') BuffyPos++;
  1118.     return String(Buffy);
  1119.   }
  1120.  
  1121. //.parse
  1122.  
  1123. String RightText(const char* CS, int NewSize)
  1124.   {
  1125.     String S=CS;
  1126.     S.Right(NewSize);
  1127.     return S;
  1128.   }
  1129.  
  1130. String TailText(const char* CS, int NewSize)
  1131.   {
  1132.     String S=CS;
  1133.     S.Tail(NewSize);
  1134.     return S;
  1135.   }
  1136.  
  1137. //.parse
  1138.  
  1139. String Trim(const char* S)
  1140.   {
  1141.     String St=S;
  1142.     St.Trim();
  1143.     return St;
  1144.   }
  1145.  
  1146. String TrimTrail(const char* S)
  1147.   {
  1148.     String St=S;
  1149.     St.TrimTrail();
  1150.     return St;
  1151.   }
  1152.  
  1153. //.parse
  1154.  
  1155. String DStr(double Num)
  1156.   {
  1157.     Bool Sign=(Num<0.0);
  1158.     double N=floor(Abs(Num));
  1159.     String S;
  1160.     while (N>0.1)
  1161.       {
  1162.         N/=10.0;
  1163.         double D=(N-floor(N));
  1164.         S=char(Round(D*10.0)+48)+S;
  1165.         N-=D;
  1166.       }
  1167.     if (Sign) S='-'+S;
  1168.     if (S.Length()==0) S='0';
  1169.     return(S);
  1170.   }
  1171.  
  1172. //.parse
  1173.  
  1174. String Spaces(int HowMany)
  1175.  {
  1176.    String S(' ',HowMany,0);
  1177.    return(S);
  1178.  }
  1179.  
  1180.  
  1181.  
  1182.